package gui;

import io.Archivo;
import io.servicios.ServiciosServidorException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import logica.AbrirArchivoException;
import logica.Nucleo;

/**
 *
 * @author Mariano Zapata
 */
public class PanelArchivosAbiertosControlador {

    private JTabbedPane pestanias;
    private JList lista;
    private JCheckBox check;
    private Nucleo nucleo;
    private DefaultListModel modelo;
    private Ventana ventana;

    public PanelArchivosAbiertosControlador(JTabbedPane pestanias, JList lista, JCheckBox check)
    {
        this.check= check;
        this.lista= lista;
        nucleo= null;
        this.pestanias= pestanias;
        modelo= new DefaultListModel();
        this.lista.setModel(modelo);
        ventana= null;
    }

    public void setNucleo(Nucleo n) {
        nucleo= n;
    }

    public void setVentana(Ventana v) {
        ventana= v;
    }

    public void abrirArchivo(Archivo a)
    {
        if (nucleo.archivoAbierto(a))
        {
            this.seleccionarEnLista(a);
            JOptionPane.showMessageDialog(ventana, "El archivo " + a.getNombre() + " ya se encuentra abierto.\n" +
                    "Verifique la barra de tareas.", "Abrir archivo", JOptionPane.INFORMATION_MESSAGE);
        }
        else
        {
            nucleo.setSistemaOcupado();
            DialogoArchivo da= new DialogoArchivo(DialogoArchivo.TIPO_OBTENER);
            da.hacerVisible(ventana);
            try {
                nucleo.abrirArchivo(a);
                this.agregarALista(a);
                da.ocultar();
                nucleo.setSistemaLibre();
            } catch (RemoteException ex) {da.ocultar();
                                          nucleo.setSistemaLibre();
                                          this.manejarExcepcion(ex, a.getNombre());}
              catch (AbrirArchivoException ex) {da.ocultar();
                                                nucleo.setSistemaLibre();
                                                JOptionPane.showMessageDialog(ventana, ex.getMessage(), "Abrir archivo",
                                                    JOptionPane.WARNING_MESSAGE);}
              catch (IOException ex) {da.ocultar();
                                      nucleo.setSistemaLibre();
                                      ventana.errorGrave(ex.getMessage());}
        }
    }

    private void agregarALista(Archivo a)
    {
        pestanias.setSelectedIndex(1);
        modelo.addElement(a);
        lista.setSelectedIndex(modelo.size() - 1);
    }

    public void archivoModificado(Archivo mod)
    {
        int indice= modelo.indexOf(mod);
        if (indice >= 0)
            modelo.set(indice, mod);
    }

    public void cerrar()
    {
        String msj= "Todos aquellos archivos que se encuentren modificados serán actualizados en el Servidor.\n\n" +
                "¿Desea continuar?";
        String falla= "Algunos archivos no pudieron cerrarse porque están siendo utilizados por aplicaciones externas.\n" +
                "Cierre dichas aplicaciones y luego vuelva a intentarlo.";
        try {
            nucleo.setSistemaOcupado();
            if (check.isSelected())
            {
                int resp= JOptionPane.showConfirmDialog(ventana, msj, "Cerrar", JOptionPane.YES_NO_OPTION,
                        JOptionPane.QUESTION_MESSAGE);
                if (resp == JOptionPane.YES_OPTION)
                {
                    if (!this.cerrarArchivosTodos()) //Éste método ya muestra el DialogoArchivo.
                        JOptionPane.showMessageDialog(ventana, falla, "Cerrar", JOptionPane.WARNING_MESSAGE);
                }
                check.setSelected(false);
            }
            else
                this.cerrarArchivoSeleccionado(); //Éste método ya muestra el DialogoArchivo.
            nucleo.setSistemaLibre();
        } catch (RemoteException ex) {ventana.errorRed(ex.getMessage());}
          catch (IOException ex) {ventana.errorGrave(ex.getMessage());}
    }

    /**
     * Cierra todos los archivos abiertos, guardando todos los que se encuentren modificados.
     * La operación de guardar se realiza sin consultar al usuario.
     *
     * @return true si se cerraron todos los archivos o falso en cualquier otro caso.
     */
    private boolean cerrarArchivosTodos() throws RemoteException, FileNotFoundException, IOException
    {
        boolean cerroTodo= true;
        int cantidad= modelo.size();
        DialogoArchivo da= new DialogoArchivo(DialogoArchivo.TIPO_TRANSFERIR);
        da.hacerVisible(ventana);
        for (int k= (cantidad - 1); k >= 0; k--)
        {
            Archivo actual= (Archivo) modelo.get(k);
            if (nucleo.cerrarArchivo(actual, actual.isModificado()))
                modelo.remove(k);
            else
                cerroTodo= false;
        }
        da.ocultar();
        return cerroTodo;
    }

    private void cerrarArchivoSeleccionado() throws RemoteException, FileNotFoundException, IOException
    {
        boolean cerro;
        String pregunta= "El archivo seleccionado ha sido modificado.\n\n¿Desea guardar los cambios?";
        String error= "El archivo seleccionado está siendo utilizado por una aplicación externa y no puede cerrarse.\n" +
                "Cierre dicha aplicación y luego vuelva a intentarlo.";
        Archivo seleccionado= (Archivo) lista.getSelectedValue();
        if (seleccionado != null)
        {
            if (seleccionado.isModificado())
            {
                int respuesta= JOptionPane.showConfirmDialog(ventana, pregunta, "Guardar", JOptionPane.YES_NO_CANCEL_OPTION,
                        JOptionPane.QUESTION_MESSAGE);
                if (respuesta == JOptionPane.CANCEL_OPTION)
                    return;
                if (respuesta == JOptionPane.YES_OPTION)
                {
                    DialogoArchivo da= new DialogoArchivo(DialogoArchivo.TIPO_TRANSFERIR);
                    da.hacerVisible(ventana);
                    cerro= this.cerrarArchivoModificado(seleccionado, true);
                    da.ocultar();
                }
                else
                    cerro= this.cerrarArchivoModificado(seleccionado, false);
            }
            else       //Se llama a éste método para que quite el archivo de la lista.
                cerro= this.cerrarArchivoModificado(seleccionado, false);
            if (!cerro)
                JOptionPane.showMessageDialog(ventana, error, "Cerrar", JOptionPane.WARNING_MESSAGE);
        }
    }

    //RETORNA TRUE SI SE CERRÓ EL ARCHIVO.
    public boolean cerrarArchivoModificado(Archivo a, boolean guardar) throws RemoteException, FileNotFoundException,
            IOException
    {
        if (nucleo.cerrarArchivo(a, guardar))
        {
            modelo.removeElement(a);
            return true;
        }
        return false;
    }

    //RETORNA TRUE SI SE CERRARON todos LOS ARCHIVOS NO MODIFICADOS.
    public boolean cerrarArchivosNoModificados() throws RemoteException, FileNotFoundException, IOException
    {
        ArrayList<Archivo> quitar= new ArrayList<Archivo>();
        boolean alls= true;
        int size= modelo.size();
        for (int k= 0; k < size; k++)
        {
            Archivo actual= (Archivo) modelo.get(k);
            if (!actual.isModificado())
            {
                if (nucleo.cerrarArchivo(actual, false))
                    quitar.add(actual);
                else
                    alls= false;
            }
        }
        for (Archivo a : quitar)
            modelo.removeElement(a);
        return alls;
    }

    public List<ItemGuardar> getArchivosModificados()
    {
        List<ItemGuardar> ret= new ArrayList<ItemGuardar>();
        int size= modelo.size();
        for (int k= 0; k < size; k++)
        {
            Archivo a= (Archivo) modelo.get(k);
            if (a.isModificado())
                ret.add(new ItemGuardar(a, true));
        }
        return ret;
    }

    public void seleccionarEnLista(Archivo a)
    {
        pestanias.setSelectedIndex(1);
        lista.setSelectedValue(a, true);
    }

    private void manejarExcepcion(RemoteException ex, String nombreArchivo)
    {
        if (ex.getCause() instanceof ServiciosServidorException)
        {
            String msj= "";
            ServiciosServidorException e= (ServiciosServidorException) ex.getCause();
            switch (e.getCodigo())
            {
                case ServiciosServidorException.ERROR_ELEMENTO_ELIMINADO:
                    msj= "El archivo " + nombreArchivo + " no se puede abrir porque\nha sido eliminado " +
                            "por otro usuario en la red.";
                    break;
                case ServiciosServidorException.ERROR_ELEMENTO_OCUPADO:
                    msj= "El archivo " + nombreArchivo + " no se puede abrir porque\n está siendo " +
                            "utilizado por otro usuario en la red.";
                    break;
                case ServiciosServidorException.ERROR_ABRIR_ARCHIVO:
                    msj= "Ha ocurrido un error al copiar el archivo " + nombreArchivo +
                            "\nen el disco rígido, por favor vuelva a intentarlo.";
                    break;
            }
            JOptionPane.showMessageDialog(ventana, msj, "Abrir archivo", JOptionPane.WARNING_MESSAGE);
        }
        else
            ventana.errorRed(ex.getMessage());
    }
}
